#include "UserDao.h"

#include <memory>
#include "UserInfo.h"
#include "muduo/base/Logging.h"

using namespace ftp;
using namespace muduo;

UserDao::UserDao()
: supportAnonymousUser_(true)
{
}

UserDao::~UserDao()
{
}

bool UserDao::addUser(const std::string& username, const std::string& password, const std::string& localRootPath, Permission permission)
{
	bool res = false;

	MutexLockGuard lock(mutex_);
	if (isAnonymousUser(username)) { // anonymous user
		if (anonymousUserInfo_) { // exist
			LOG_ERROR << "Fail to add user " << username << " as \"anonymous\": the anonymous user is already existing.";
			res = false;
		}
		else { // not exist
			anonymousUserInfo_ = std::make_shared<UserInfo>(UserInfo::defaultAnonymousUsername(), password, localRootPath, permission);
			LOG_DEBUG << "Successfully add user \"" << username << "\".";
			res = true;
		}
	}
	else { // non-anonymous user
		auto it = database_.find(username);
		if (it != database_.end()) { // exist
			LOG_ERROR << "Fail to add user \"" << username << "\"";
			res = false;
		}
		else { // not exist
			database_.emplace(username, std::shared_ptr<UserInfo>(new UserInfo(username, password, localRootPath, permission)));
			LOG_DEBUG << "Successfully add user \"" << username << "\".";
			res = true;
		}
	}
	return res;
}

std::shared_ptr<UserInfo> UserDao::getUserInfo(const std::string& username, const std::string& password) const
{
	MutexLockGuard lock(mutex_);

	// 2 kind of user: anonymous user, general user
	if (isAnonymousUser(username)) {
		return anonymousUserInfo_;
	}
	else {
		auto it = database_.find(username);
		if (it != database_.end() && it->second->password_ == password) {
			return it->second;
		}
		else {
			return nullptr;
		}
	}
}

bool UserDao::isAnonymousUser(const std::string& username) const
{
	return supportAnonymousUser_ && (username.empty() || username == UserInfo::defaultAnonymousUsername());
}

void UserDao::enableAnonymousUser()
{
	setSupportAnonymousUser(true);
}

void UserDao::disableAnonymousUser()
{
	setSupportAnonymousUser(false);
}

void UserDao::setSupportAnonymousUser(bool val)
{
	supportAnonymousUser_ = val;
}